package com.droid.lib.controls.widget;

import java.util.ArrayList;
import java.util.List;

import android.R;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;

/**
 * 九宫格控件
 * 
 * @author Administrator
 *
 */
public class Lock9View extends ViewGroup {

	/**
	 * 节点相关定义
	 */
	private List<NodeView> nodeList = new ArrayList<NodeView>(); // 已经连线的节点链表
	private float x; // 当前手指坐标x
	private float y; // 当前手指坐标y

	/**
	 * 布局和节点样式
	 */
	private Drawable nodeSrc;
	private Drawable nodeOnSrc;
	private float nodeSize; // 节点大小，如果不为0，则忽略内边距和间距属性
	private float nodeAreaExpand; // 对节点的触摸区域进行扩展
	private int nodeOnAnim; // 节点点亮时的动画
	private int lineColor;
	private float lineWidth;
	private float padding; // 内边距
	private float spacing; // 节点间隔距离

	/**
	 * 自动连接中间节点
	 */
	private boolean autoLink;

	/**
	 * 震动管理器
	 */
	private Vibrator vibrator;
	private boolean enableVibrate;
	private int vibrateTime;

	/**
	 * 画线用的画笔
	 */
	private Paint paint;

	/**
	 * 密码构建器
	 */
	private StringBuilder passwordBuilder = new StringBuilder();

	/**
	 * 结果回调监听器接口
	 */
	private CallBack callBack;

	public interface CallBack {

		void onFinish(String password);

	}

	public void setCallBack(CallBack callBack) {
		this.callBack = callBack;
	}
	/**
	 * 构造函数
	 */
	public Lock9View(Context context) {
		super(context);
		init(context, null, 0, 0);
	}

	
    /**
     * 九宫格
     * @param context 
     * @param nodeSrc 点击前效果
     * @param nodeOnSrc 点击后效果
     * @param lineColor 线的颜色
     */
	public Lock9View(Context context, int nodeSrc, int nodeOnSrc, int lineColor) {
		super(context);
		init(context, context.getResources().getDrawable(nodeSrc),context.getResources().getDrawable(nodeOnSrc) , lineColor);
	}

	public Lock9View(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs, 0, 0);
	}
	public Lock9View(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init(context, attrs, defStyleAttr, 0);
	}

	/**
	 * 初始化
	 */
	public void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
		// 获取定义的属性
		//// 小球默认效果
		nodeSrc = nodeSrc == null ? getResources().getDrawable(R.drawable.ic_media_play) : nodeSrc;
		// 小球点击效果
		nodeOnSrc = getResources().getDrawable(R.drawable.ic_media_pause);
		nodeSize = 100;
		// If you want to draw a small node with a bigger touch area, please
		// user
		nodeAreaExpand = 100;
		// Animation
		nodeOnAnim = 0;
		// 线颜色
		lineColor = R.color.holo_orange_light;
		// 线宽度
		lineWidth = 16;
		padding = 0;
		spacing = 0;
		// AutoLink
		autoLink = false;
		// 振动
		enableVibrate = false;
		vibrateTime = 20;

		// 初始化振动器
		if (enableVibrate && !isInEditMode()) {
			vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
		}

		// 初始化画笔
		paint = new Paint(Paint.DITHER_FLAG);
		paint.setStyle(Style.STROKE);
		paint.setStrokeWidth(lineWidth);
		// 线颜色
		paint.setColor(Color.rgb(243, 163, 37));
		paint.setAntiAlias(true); // 抗锯齿

		// 构建node
		for (int n = 0; n < 9; n++) {
			NodeView node = new NodeView(getContext(), n + 1);
			addView(node);
		}

		// 清除FLAG，否则 onDraw() 不会调用，原因是 ViewGroup 默认透明背景不需要调用 onDraw()
		setWillNotDraw(false);
	}
	public void init(Context context, Drawable nodeSrc, Drawable nodeOnSrc, int lineColor) {
		this.nodeSrc = nodeSrc;
		// 小球点击效果
		this.nodeOnSrc = nodeOnSrc;
		this.lineColor = lineColor;
		// 初始化振动器
		if (enableVibrate && !isInEditMode()) {
			vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
		}
		nodeSize = 100;
		// If you want to draw a small node with a bigger touch area, please
		// user
		nodeAreaExpand = 100;
		// Animation
		nodeOnAnim = 0;
		// 线宽度
		lineWidth = 16;
		padding = 0;
		spacing = 0;
		// AutoLink
		autoLink = false;
		// 振动
		enableVibrate = false;
		vibrateTime = 20;
		// 初始化画笔
		paint = new Paint(Paint.DITHER_FLAG);
		paint.setStyle(Style.STROKE);
		paint.setStrokeWidth(lineWidth);
		// 线颜色
		paint.setColor(Color.rgb(243, 163, 37));
		paint.setAntiAlias(true); // 抗锯齿
		
		// 构建node
		for (int n = 0; n < 9; n++) {
			NodeView node = new NodeView(getContext(), n + 1);
			addView(node);
		}
		// 清除FLAG，否则 onDraw() 不会调用，原因是 ViewGroup 默认透明背景不需要调用 onDraw()
		setWillNotDraw(false);
	}

	/**
	 * TODO 我们让高度等于宽度 - 方法有待验证
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int size = measureSize(widthMeasureSpec); // 测量宽度
		setMeasuredDimension(size, size);
	}

	/**
	 * TODO 测量长度
	 */
	private int measureSize(int measureSpec) {
		int specMode = MeasureSpec.getMode(measureSpec); // 得到模式
		int specSize = MeasureSpec.getSize(measureSpec); // 得到尺寸
		switch (specMode) {
		case MeasureSpec.EXACTLY:
		case MeasureSpec.AT_MOST:
			return specSize;
		default:
			return 0;
		}
	}

	/**
	 * 在这里进行node的布局
	 */
	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		if (changed) {
			if (nodeSize > 0) { // 如果设置nodeSize值，则将节点绘制在九等分区域中心
				float areaWidth = (right - left) / 3;
				for (int n = 0; n < 9; n++) {
					NodeView node = (NodeView) getChildAt(n);
					// 获取3*3宫格内坐标
					int row = n / 3;
					int col = n % 3;
					// 计算实际的坐标
					int l = (int) (col * areaWidth + (areaWidth - nodeSize) / 2);
					int t = (int) (row * areaWidth + (areaWidth - nodeSize) / 2);
					int r = (int) (l + nodeSize);
					int b = (int) (t + nodeSize);
					node.layout(l, t, r, b);
				}
			} else { // 否则按照分割边距布局，手动计算节点大小
				float nodeSize = (right - left - padding * 2 - spacing * 2) / 3;
				for (int n = 0; n < 9; n++) {
					NodeView node = (NodeView) getChildAt(n);
					// 获取3*3宫格内坐标
					int row = n / 3;
					int col = n % 3;
					// 计算实际的坐标，要包括内边距和分割边距
					int l = (int) (padding + col * (nodeSize + spacing));
					int t = (int) (padding + row * (nodeSize + spacing));
					int r = (int) (l + nodeSize);
					int b = (int) (t + nodeSize);
					node.layout(l, t, r, b);
				}
			}
		}
	}

	/**
	 * 在这里处理手势
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_MOVE:
			x = event.getX(); // 这里要实时记录手指的坐标
			y = event.getY();
			NodeView currentNode = getNodeAt(x, y);
			if (currentNode != null && !currentNode.isHighLighted()) { // 碰触了新的未点亮节点
				if (nodeList.size() > 0) { // 之前有点亮的节点
					if (autoLink) { // 开启了中间节点自动连接
						NodeView lastNode = nodeList.get(nodeList.size() - 1);
						NodeView middleNode = getNodeBetween(lastNode, currentNode);
						if (middleNode != null && !middleNode.isHighLighted()) { // 存在中间节点没点亮
							// 点亮中间节点
							middleNode.setHighLighted(true, true);
							nodeList.add(middleNode);
						}
					}
				}
				// 点亮当前触摸节点
				currentNode.setHighLighted(true, false);
				nodeList.add(currentNode);
			}
			// 有点亮的节点才重绘
			if (nodeList.size() > 0) {
				invalidate();
			}
			break;
		case MotionEvent.ACTION_UP:
			if (nodeList.size() > 0) { // 有点亮的节点
				// 回调结果
				if (callBack != null) {
					// 生成密码
					passwordBuilder.setLength(0);
					for (NodeView nodeView : nodeList) {
						passwordBuilder.append(nodeView.getNum());
					}
					// callback
					callBack.onFinish(passwordBuilder.toString());
				}
				// 清除状态
				nodeList.clear();
				for (int n = 0; n < getChildCount(); n++) {
					NodeView node = (NodeView) getChildAt(n);
					node.setHighLighted(false, false);
				}
				// 通知重绘
				invalidate();
			}
			break;
		}
		return true;
	}

	/**
	 * 系统绘制回调-主要绘制连线
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		// 先绘制已有的连线
		for (int n = 1; n < nodeList.size(); n++) {
			NodeView firstNode = nodeList.get(n - 1);
			NodeView secondNode = nodeList.get(n);
			canvas.drawLine(firstNode.getCenterX(), firstNode.getCenterY(), secondNode.getCenterX(),
					secondNode.getCenterY(), paint);
		}
		// 如果已经有点亮的点，则在点亮点和手指位置之间绘制连线
		if (nodeList.size() > 0) {
			NodeView lastNode = nodeList.get(nodeList.size() - 1);
			canvas.drawLine(lastNode.getCenterX(), lastNode.getCenterY(), x, y, paint);
		}
	}

	/**
	 * 获取给定坐标点的Node，返回null表示当前手指在两个Node之间
	 */
	private NodeView getNodeAt(float x, float y) {
		for (int n = 0; n < getChildCount(); n++) {
			NodeView node = (NodeView) getChildAt(n);
			if (!(x >= node.getLeft() - nodeAreaExpand && x < node.getRight() + nodeAreaExpand)) {
				continue;
			}
			if (!(y >= node.getTop() - nodeAreaExpand && y < node.getBottom() + nodeAreaExpand)) {
				continue;
			}
			return node;
		}
		return null;
	}

	/**
	 * 获取两个Node中间的Node，返回null表示没有中间node
	 */
	private NodeView getNodeBetween(NodeView na, NodeView nb) {
		if (na.getNum() > nb.getNum()) { // 保证 na 小于 nb
			NodeView nc = na;
			na = nb;
			nb = nc;
		}
		if (na.getNum() % 3 == 1 && nb.getNum() - na.getNum() == 2) { // 水平的情况
			return (NodeView) getChildAt(na.getNum());
		} else if (na.getNum() <= 3 && nb.getNum() - na.getNum() == 6) { // 垂直的情况
			return (NodeView) getChildAt(na.getNum() + 2);
		} else if ((na.getNum() == 1 && nb.getNum() == 9) || (na.getNum() == 3 && nb.getNum() == 7)) { // 倾斜的情况
			return (NodeView) getChildAt(4);
		} else {
			return null;
		}
	}

	/**
	 * 节点描述类
	 */
	private class NodeView extends View {

		private int num;
		private boolean highLighted = false;

		@SuppressWarnings("deprecation")
		public NodeView(Context context, int num) {
			super(context);
			this.num = num;
			setBackgroundDrawable(nodeSrc);
		}

		public boolean isHighLighted() {
			return highLighted;
		}

		@SuppressWarnings("deprecation")
		public void setHighLighted(boolean highLighted, boolean isMid) {
			if (this.highLighted != highLighted) {
				this.highLighted = highLighted;
				if (nodeOnSrc != null) { // 没有设置高亮图片则不变化
					setBackgroundDrawable(highLighted ? nodeOnSrc : nodeSrc);
				}
				if (nodeOnAnim != 0) { // 播放动画
					if (highLighted) {
						startAnimation(AnimationUtils.loadAnimation(getContext(), nodeOnAnim));
					} else {
						clearAnimation();
					}
				}
				if (enableVibrate && !isMid) { // 震动
					if (highLighted) {
						vibrator.vibrate(vibrateTime);
					}
				}
			}
		}

		public int getCenterX() {
			return (getLeft() + getRight()) / 2;
		}

		public int getCenterY() {
			return (getTop() + getBottom()) / 2;
		}

		public int getNum() {
			return num;
		}

	}

}
